package com.ruoyi.dynamic.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.common.core.constant.SecurityConstants;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.enums.CacheKey;
import com.ruoyi.common.core.pojo.result.PageUtils;
import com.ruoyi.common.core.pojo.result.Pages;
import com.ruoyi.common.core.utils.*;
import com.ruoyi.common.redis.cache.CacheTemplate;
import com.ruoyi.common.redis.service.RedisService;
import com.ruoyi.dynamic.mapper.RoomMapper;
import com.ruoyi.dynamic.model.config.RtcConfig;
import com.ruoyi.dynamic.model.constant.DynamicConstant;
import com.ruoyi.dynamic.model.constant.ParamCacheKey;
import com.ruoyi.dynamic.model.constant.PrefixIcon;
import com.ruoyi.dynamic.model.constant.RoomChatRoomKvConstant;
import com.ruoyi.dynamic.model.pojo.entity.*;
import com.ruoyi.dynamic.model.pojo.request.app.*;
import com.ruoyi.dynamic.model.pojo.request.crm.CrmRoomSearchRequest;
import com.ruoyi.dynamic.model.pojo.request.sheng.AppShengWebHookRequest;
import com.ruoyi.dynamic.model.pojo.result.app.*;
import com.ruoyi.dynamic.model.pojo.result.crm.CrmRoomInfoResult;
import com.ruoyi.dynamic.service.*;
import com.ruoyi.system.api.RemoteAppUserService;
import com.ruoyi.system.api.model.user.AppUser;
import io.agora.media.RtcTokenBuilder;
import io.rong.RongCloud;
import io.rong.methods.chatroom.Chatroom;
import io.rong.models.chatroom.ChatroomDataModel;
import io.rong.models.chatroom.ChatroomModel;
import io.rong.models.response.ResponseResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * <p>
 * 房间表 服务实现类
 * </p>
 *
 * @author ${author}
 * @since 2024-11-23
 */

@Slf4j
@Service
public class RoomServiceImpl extends ServiceImpl<RoomMapper, Room> implements IRoomService {

    @Autowired
    private RemoteAppUserService remoteAppUserService;
    @Autowired
    private IRoomTypeService iRoomTypeService;
    @Autowired
    private RtcConfig rtcConfig;
    @Autowired
    private RongCloud rongCloud;
    @Autowired
    private IRoomMaiRecordService roomMaiRecordService;
    @Autowired
    private IRoomRecordService roomRecordService;
    @Autowired
    private RedisService redisService;
    @Autowired
    private RoomMapper roomMapper;
    @Autowired
    private IRoomCoverService iRoomCoverService;
    @Autowired
    private IRoomGiftRecordService iRoomGiftRecordService;
    @Autowired
    private IRoomSetService iRoomSetService;
    @Autowired
    private IMessageService messageService;
    @Autowired
    private IRoomUserPostPermissionService iRoomUserPostPermissionService;
    @Autowired
    private IRoomBanUserService iRoomBanUserService;
    @Autowired
    private IParamService iParamService;

    @Override
    public Room getRoomByChannelName(String channelName) {
        return lambdaQuery().eq(Room::getRoomNumber, channelName)
                .one();
    }

    @Override
    public AppRoomSetResult getUserRoomSet(Long userId) {
        return iRoomSetService.getUserRoomSet(userId);
    }

    @Override
    public AppUser verifyIsBoos(Long userId) {
        R<AppUser> userInfo = remoteAppUserService.getUserInfo(userId, SecurityConstants.APP);
        AppUser data = userInfo.getData();
        Assert.notNull(data, "获取主持信息失败");
        Assert.isTrue(data.getIsAuth().equals(DynamicConstant.IsAutu.YES), "请先实名认证");
        Assert.isTrue(data.getIdentity().equals(DynamicConstant.Identity.HOST), "请先申请主持!");
        return data;
    }

    @Override
    public AppCreateRoomResult createRoom(Long userId, AppCreateRoomRequest request) {
        AppUser data = this.verifyIsBoos(userId);

        RoomType verify = iRoomTypeService.verify(request.getRoomTypeId());

        AppRoomSetResult userRoomSet = iRoomSetService.getUserRoomSet(userId);

        String number = CodeMaxIdUtil.genUniqueKey(PrefixIcon.ROOM);
        String groupId = CodeMaxIdUtil.genUniqueKey(PrefixIcon.GROUP);
        //TODO测试用一个群组
        Assert.isTrue(createRongCloundRoom(String.valueOf(userId), number, groupId, data.getNickName()), "创建聊天室失败请稍后再试");
        String rtcNumber = this.createRtcNumber(number, userId);
        Assert.isTrue(StringUtils.hasText(rtcNumber), "创建房间失败请联系客服");

        Room room = new Room();
        room.setRoomNumber(number);
        room.setBackgroundUrl(request.getBackgroundUrl());
        room.setUserId(userId);
        room.setCreateTime(new Date());
        room.setName(data.getNickName());
        room.setContent(request.getContent());
        room.setSoundNumber(rtcNumber);
        room.setStatus(DynamicConstant.RoomStatus.YES);
        room.setGroupId(groupId);
        room.setRoomTypeName(verify.getName());
        room.setSex(data.getSex());
        room.setUserPhoto(data.getPhoto());
        room.setRoomTypeId(request.getRoomTypeId());
        room.setCoverImgUrl(userRoomSet.getRoomCoverImg());
        save(room);
        CacheTemplate.setCache(CacheKey.ROOM_INFO.getKey(String.valueOf(room.getId())), room, 1L, TimeUnit.DAYS);
        this.roomUser(room, userId, data);
        //异步执行相关操作
        this.clearRoomMai(String.valueOf(data.getId()), userId);
        return AppCreateRoomResult.builder()
                .backgroundUrl(room.getBackgroundUrl())
                .content(room.getContent())
                .name(room.getName())
                .roomTypeId(request.getRoomTypeId())
                .roomTypeName(verify.getName())
                .soundNumber(rtcNumber)
                .status(room.getStatus())
                .userId(userId)
                .roomId(room.getId())
                .build()
                ;
    }

    //清除旧房间麦位
    public void clearRoomMai(String roomNumber, Long userId) {
        String key = CacheKey.ROOM_MAI.getKey(userId);
        String cacheKey = key.replaceAll("\\{roomNumber}", roomNumber);
        CacheTemplate.clear(cacheKey);
    }


    //清除房间麦位
    public void clearRoom(Long id) {
        String key = CacheKey.ROOM_MAI.getKey("*");
        String cacheKey = key.replaceAll("\\{roomNumber}", String.valueOf(id));
        CacheTemplate.clear(cacheKey);
    }


    //销毁聊天室
    @Async
    public void destroyRoom(String chatRoomId) {
        try {
            ChatroomModel model = new ChatroomModel();
            model.setId(chatRoomId);
            Chatroom chatroom = rongCloud.chatroom;
            chatroom.destroy(model);
        } catch (Exception e) {
            e.printStackTrace();
            log.info("销毁房间-----------------e={}", e.toString());
        }

    }


    //房主加入麦位0号位置
    @Async
    public void roomUser(Room verify, Long userId, AppUser data) {
        String key = CacheKey.ROOM_MAI.getKey(String.valueOf(userId));
        String cacheKey = key.replaceAll("\\{roomNumber}", String.valueOf(verify.getId()));
        AppRoomMaiUserResult build = AppRoomMaiUserResult.builder()
                .maiNum(0)
                .nickName(data.getNickName())
                .photo(data.getPhoto())
                .id(userId)
                .build();
        CacheTemplate.setCache(cacheKey, build, 1L, TimeUnit.DAYS);

        if (verify.getRoomTypeId().equals(4L)) {
            AppRoomHeatResult result = AppRoomHeatResult.builder()
                    .content("")
                    .id(verify.getId())
                    .status(verify.getStatus())
                    .stepName("准备环节")
                    .build();
            //心动交友
            messageService.setRoomChatRoomAttr(verify.getGroupId(), verify.getUserId().toString(), RoomChatRoomKvConstant.ROOM_HEAT_ID, JSONObject.toJSONString(result),
                    0, "", ""
            );
        }

    }


    @Override
    public boolean createRongCloundRoom(String userId, String roomNumber, String groupId, String name) {
        try {
            ChatroomDataModel model = new ChatroomDataModel();
            model.setId(groupId);
            model.setDestroyType(1);
            model.setDestroyTime(10080);//7天
            Chatroom group = rongCloud.chatroom;
            ResponseResult result = group.createV2(model);
            log.info("融云创建聊天室返回信息：{}", result.toString());
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }


    @Override
    public String createRtcNumber(String number, Long userId) {
        RtcTokenBuilder shengToken = new RtcTokenBuilder();
        int timestamp = (int) (System.currentTimeMillis() / 1000L + DynamicConstant.RoomExpirationTime.time);
        try {
            return shengToken.buildTokenWithUid(rtcConfig.getAppKey(), rtcConfig.getAppSecret(), number, Math.toIntExact(userId), RtcTokenBuilder.Role.Role_Subscriber, timestamp);
        } catch (Exception e) {
            log.info("创建声网房间失败------- e=#{}", e.toString());
        }
        return "";
    }

    @Override
    public AppRoomInfoResult info(Long userId, Long id) {
        Room record = verify(id);
        Integer data = 0;
        try {
            R<Integer> userIsAttention = remoteAppUserService.getUserIsAttention(userId, record.getUserId(), SecurityConstants.APP);
            data = userIsAttention.getData();
        } catch (Exception e) {

        }
        return AppRoomInfoResult
                .builder()
                .content(record.getContent())
                .backgroundUrl(record.getBackgroundUrl())
                .id(record.getId())
                .name(record.getName())
                .roomNumber(record.getRoomNumber())
                .soundNumber(record.getSoundNumber())
                .userId(record.getUserId())
                .roomTypeId(record.getRoomTypeId())
                .status(record.getStatus())
                .sex(record.getSex())
                .isAttention(data)
                .groupId(record.getGroupId())
                .roomTypeId(record.getRoomTypeId())
                .roomTypeName(record.getRoomTypeName())
                .userPhoto(record.getUserPhoto())
                .coverImgUrl(record.getCoverImgUrl())
                .userTotalCount(roomRecordService.roomUserTotalCount(record.getId()))
                .build()
                ;
    }

    /**
     * 统一执行上麦方法
     *
     * @param userId
     * @param id
     * @param location
     * @param type
     * @param groupId
     * @param verifyUserId
     */
    @Async
    public void passUpMai(Long userId, Long id, Integer location, Integer type, String groupId, Long verifyUserId, Integer starLocation) {
        R<AppUser> userInfo = remoteAppUserService.getUserInfo(userId, SecurityConstants.APP);
        AppUser data = userInfo.getData();
        String key = "";
        if (type.equals(DynamicConstant.MaiType.MAI)) {
            key = CacheKey.ROOM_MAI.getKey(String.valueOf(userId));
        }
        if (type.equals(DynamicConstant.MaiType.LIAN)) {
            key = CacheKey.ROOM_LIAN.getKey(String.valueOf(userId));
        }
        String cacheKey = key.replaceAll("\\{roomNumber}", String.valueOf(id));
        AppRoomMaiUserResult result = CacheTemplate.getCache(cacheKey, AppRoomMaiUserResult.class, () -> {
            AppRoomMaiUserResult build = AppRoomMaiUserResult.builder()
                    .maiNum(location)
                    .nickName(data.getNickName())
                    .photo(data.getPhoto())
                    .id(data.getId())
                    .isSilence(DynamicConstant.CheckStatus.NO)
                    .location(starLocation)
                    .build();
            CacheTemplate.setCache(cacheKey, build, 1L, TimeUnit.DAYS);
            return build;
        });
        Assert.notNull(result, "请更换麦位!");
    }


    @Override
    public boolean upMai(AppRoomMaiRequest request, Long userId) {
        R<AppUser> userInfo = remoteAppUserService.getUserInfo(request.getUserId(), SecurityConstants.APP);
        AppUser data = userInfo.getData();
        Room verify = verify(request.getRoomId());
        this.passUpMai(request.getUserId(), verify.getId(), request.getLocation(), request.getType(), verify.getGroupId(), verify.getUserId(), DynamicConstant.MomentLocation.Heart);
        roomMaiRecordService.add(verify.getId(), verify.getRoomNumber(), userId, request.getLocation(), request.getType(), DynamicConstant.IsOnLine.Leave, data.getPhoto(), data.getNickName(), DynamicConstant.MomentLocation.Heart);
        return true;
    }

    @Override
    public Room verify(Long id) {
        Room room = CacheTemplate.getCache(CacheKey.ROOM_INFO.getKey(String.valueOf(id)), Room.class, () -> {
            Optional<Room> user = lambdaQuery()
                    .eq(Room::getId, id)
                    .oneOpt();
            if (!user.isPresent()) return null;
            CacheTemplate.setCache(CacheKey.ROOM_INFO.getKey(String.valueOf(id)), user.get(), 1L, TimeUnit.DAYS);
            return user.get();
        });
        Assert.notNull(room, "此房间不存在");
        Assert.isTrue(room.getStatus().equals(DynamicConstant.RoomStatus.YES), "此房间已关闭");
        return room;
    }

    @Override
    public List<AppRoomMaiUserResult> maiUsers(Long roomId, Integer type, boolean flag, boolean my, Long userId, Integer maiNum) {
        Room verify = verify(roomId);
        String key = "";
        if (type.equals(DynamicConstant.MaiType.MAI)) {
            key = CacheKey.ROOM_MAI.getKey("*");
        } else if (type.equals(DynamicConstant.MaiType.LIAN)) {
            key = CacheKey.ROOM_LIAN.getKey("*");
        } else {
            Assert.isTrue(false, "类型不对");
        }
        String cacheKey = key.replaceAll("\\{roomNumber}", String.valueOf(verify.getId()));
        Collection<String> keys = redisService.keys(cacheKey);
        if (keys.isEmpty()) return CollectionUtils.emptyList();

        List<AppRoomMaiUserResult> collect = keys.stream().map(res -> {
            return CacheTemplate.getCache(res, AppRoomMaiUserResult.class);
        }).collect(Collectors.toList());

        if (!flag) {
            collect = collect.stream().filter(res -> !res.getId().equals(verify.getUserId())).collect(Collectors.toList());
        }
        if (!my && !userId.equals(0L)) {
            collect = collect.stream().filter(res -> !res.getId().equals(userId)).collect(Collectors.toList());
        }
        if (maiNum > 0) {
            collect = collect.stream().filter(res -> !res.getMaiNum().equals(maiNum)).collect(Collectors.toList());
        }
        return CollectionUtil.sort(collect, Comparator.comparing(AppRoomMaiUserResult::getMaiNum));
    }

    @Override
    public boolean downMai(AppRoomMaiRequest request, Long userId) {
        Room verify = verify(request.getRoomId());
        String key = CacheKey.ROOM_MAI.getKey(String.valueOf(userId));
        String cacheKey = key.replaceAll("\\{roomNumber}", String.valueOf(verify.getId()));
        CacheTemplate.clear(cacheKey);
        roomMaiRecordService.lambdaUpdate()
                .eq(RoomMaiRecord::getUserId, userId)
                .eq(RoomMaiRecord::getRoomId, request.getRoomId())
                .set(RoomMaiRecord::getEndTime, new Date())
                .set(RoomMaiRecord::getStatus, DynamicConstant.MaiStatus.Not)
                .update();
        return true;
    }

    @Override
    public AppRoomInfoResult enter(Long userId, Long id) {
        Room verify = verify(id);
        Assert.isTrue(!iRoomBanUserService.isBlockByUser(verify.getId(), userId, DynamicConstant.PermissionIds.Ban), "您已被主持拉黑无法加入房间");
        String rtcNumber = this.createRtcNumber(verify.getRoomNumber(), userId);

        return AppRoomInfoResult.builder()
                .status(verify.getStatus())
                .roomTypeId(verify.getRoomTypeId())
                .userId(verify.getUserId())
                .soundNumber(rtcNumber)
                .roomNumber(verify.getRoomNumber())
                .name(verify.getName())
                .backgroundUrl(verify.getBackgroundUrl())
                .id(verify.getId())
                .content(verify.getContent())
                .roomTypeName(verify.getRoomTypeName())
                .groupId(verify.getGroupId())
                .build()
                ;
    }

    @Override
    public Pages<AppRoomInfoResult> listPage(AppRoomSearchRequest request, Long userId) {
        Page<Room> roomPage = PageUtils.initPage(request, Room.class);
        //关注
        if (request.isAttention()) {
            R<Set<Long>> userAttention = remoteAppUserService.getUserAttention(userId, SecurityConstants.APP);
            if (userAttention.getData().isEmpty()) return PageUtils.pages(roomPage, CollectionUtils.emptyList());
            request.setUserIds(userAttention.getData());
        }
        Page<AppRoomInfoResult> page = roomMapper.listPage(request, roomPage);
        return PageUtils.pages(page);
    }

    @Override
    public List<String> cover(Long userId) {
        return iRoomCoverService.getRoomCoverByUser(userId);
    }

    @Override
    public boolean updateCover(Long userId, AppUpdateRoomCoverRequest request) {
        iRoomCoverService.lambdaUpdate().eq(RoomCover::getUserId, userId).remove();
        List<RoomCover> collect = request.getImgUrl().stream().map(res -> {
            RoomCover roomCover = new RoomCover();
            roomCover.setUserId(userId);
            roomCover.setImgUrl(res);
            return roomCover;
        }).collect(Collectors.toList());
        return iRoomCoverService.saveBatch(collect);
    }


    @Override
    public Pages<AppRoomMaiUserResult> lineListPage(AppRoomProgarmSearchRequest pageSearchParam, Long userId) {
        Page<RoomMaiRecord> roomMaiRecordPage = PageUtils.initPage(pageSearchParam, RoomMaiRecord.class);
        Page<RoomMaiRecord> page = roomMaiRecordService.lambdaQuery()
                .eq(RoomMaiRecord::getRoomId, pageSearchParam.getRoomId())
                .eq(!CommonUtils.isNull(pageSearchParam.getStarLocation()), RoomMaiRecord::getStarLocation, pageSearchParam.getStarLocation())
                .eq(RoomMaiRecord::getStatus, DynamicConstant.CheckStatus.NO)
                .eq(RoomMaiRecord::getType, pageSearchParam.getType())
                .orderByAsc(RoomMaiRecord::getCreateTime)
                .page(roomMaiRecordPage);

        List<AppRoomMaiUserResult> collect = page.getRecords().stream().map(res -> {
            return AppRoomMaiUserResult
                    .builder()
                    .id(res.getUserId())
                    .photo(res.getUserPhoto())
                    .nickName(res.getUserNickName())
                    .maiNum(res.getMaiNum())
                    .beforeTime(DateUtils.format(res.getCreateTime()))
                    .isLine(userId.equals(res.getUserId()))
                    .recordId(res.getId())
                    .isSilence(res.getIsSilence())
                    .build();
        }).collect(Collectors.toList());

        return PageUtils.pages(page, collect);
    }

    @Override
    public boolean cancelLine(Long id, Long userId) {
        verify(id);
        return roomMaiRecordService.lambdaUpdate().eq(RoomMaiRecord::getRoomId, id).eq(RoomMaiRecord::getUserId, userId).remove();
    }

    @Override
    public AppRoomOverResult leave(Long id, Long userId) {
        Room verify = verify(id);
        if (verify.getUserId().equals(userId)) {
            verify.setCloseTime(new Date());
            verify.setStatus(DynamicConstant.CheckStatus.NO);
            updateById(verify);
            CacheTemplate.setCache(CacheKey.ROOM_INFO.getKey(String.valueOf(id)), verify, 1L, TimeUnit.DAYS);
            this.clearRoom(verify.getId());
            this.destroyRoom(verify.getGroupId());
            R<AppUser> userInfo = remoteAppUserService.getUserInfo(verify.getUserId(), SecurityConstants.APP);
            AppUser data = userInfo.getData();
            return AppRoomOverResult.builder()
                    .id(verify.getId())
                    .roomUserId(verify.getUserId())
                    .roomUserNickName(data.getNickName())
                    .roomUserPhoto(data.getPhoto())
                    .userTotalCount(roomRecordService.roomUserTotalCount(id))
                    .giveCount(iRoomGiftRecordService.countGiveCount(id))
                    .liveTime(DateUtils.timeDistanceSen(verify.getCloseTime(), verify.getCreateTime()))
                    .newAttentionCount(roomRecordService.attentionCount(id))
                    .lineMaxTime(roomRecordService.getMaxLook(id))
                    .lineMaxCount(roomRecordService.roomUserLineCount(id))
                    .build()
                    ;
        }
        return null;
    }

    @Override
    public void downMaiAll(Long id, Long userId) {
        Room verify = verify(id);
        Assert.isTrue(verify.getUserId().equals(userId), "您无此权限操作");
        String key = CacheKey.ROOM_MAI.getKey("*");
        String cacheKey = key.replaceAll("\\{roomNumber}", String.valueOf(verify.getId()));
        CacheTemplate.clear(cacheKey);

        roomMaiRecordService.
                lambdaUpdate()
                .eq(RoomMaiRecord::getUserId, verify.getId())
                .set(RoomMaiRecord::getStatus, DynamicConstant.CheckStatus.YES)
                .update();
    }

    public void downMaiAndLineByUser(Long userId, Long id) {
        String key = CacheKey.ROOM_MAI.getKey(String.valueOf(userId));
        String cacheKey = key.replaceAll("\\{roomNumber}", String.valueOf(id));
        CacheTemplate.clear(cacheKey);

        String lineKey = CacheKey.ROOM_LIAN.getKey(String.valueOf(userId));
        String lineCacheKey = lineKey.replaceAll("\\{roomNumber}", String.valueOf(id));
        CacheTemplate.clear(lineCacheKey);
    }


    @Override
    public void downMaiByUser(AppRoomDownMaiRequest request, Long userId) {
        Room verify = verify(request.getRoomId());
        Assert.isTrue(verify.getUserId().equals(userId), "您无此权限操作");
        String key = CacheKey.ROOM_MAI.getKey(String.valueOf(request.getUserId()));
        String cacheKey = key.replaceAll("\\{roomNumber}", String.valueOf(verify.getId()));
        CacheTemplate.clear(cacheKey);
        roomMaiRecordService.
                lambdaUpdate()
                .eq(RoomMaiRecord::getRoomId, request.getRoomId())
                .eq(RoomMaiRecord::getUserId, request.getRoomId())
                .set(RoomMaiRecord::getStatus, DynamicConstant.CheckStatus.YES)
                .update();
    }

    @Override
    public Pages<AppRoomUserInfoResult> userListPage(AppRoomUserSearchRequest request, Long userId) {
        Room verify = verify(request.getRoomId());
        String roomHeat = iParamService.selectConfigByKey(ParamCacheKey.ROOM_HEAT);


        Page<RoomRecord> page = PageUtils.initPage(request, RoomRecord.class);
        Page<AppRoomUserInfoResult> resultPage = roomMapper.userListPage(request, page, new BigDecimal(roomHeat), verify.getUserId());
        return PageUtils.pages(resultPage);
    }

    @Override
    public Integer isSilence(AppRoomDownMaiRequest request, Long userId) {
        Room verify = verify(request.getRoomId());

        String key = "";
        if (request.getType().equals(DynamicConstant.MaiType.MAI)) {
            key = CacheKey.ROOM_MAI.getKey(String.valueOf(request.getUserId()));
        }
        if (request.getType().equals(DynamicConstant.MaiType.LIAN)) {
            key = CacheKey.ROOM_MAI.getKey(String.valueOf(request.getUserId()));
        }
        String cacheKey = key.replaceAll("\\{roomNumber}", String.valueOf(verify.getId()));
        AppRoomMaiUserResult cache = CacheTemplate.getCache(cacheKey, AppRoomMaiUserResult.class);
        Assert.notNull(cache, "该用户不在麦上无法操作");
        cache.setIsSilence(request.getIsSilence());
        CacheTemplate.setCache(cacheKey, cache, 1L, TimeUnit.DAYS);

        roomMaiRecordService
                .lambdaUpdate()
                .eq(RoomMaiRecord::getUserId, request.getUserId())
                .eq(RoomMaiRecord::getRoomId, request.getRoomId())
                .set(RoomMaiRecord::getIsSilence, request.getIsSilence())
                .update();
        return request.getIsSilence();
    }

    @Override
    public Integer lineNum(Long id, Long userId) {
        String key = CacheKey.ROOM_ONLINE.getKey("*");
        String cacheKey = key.replaceAll("\\{roomNumber}", String.valueOf(id));
        Collection<String> keys = redisService.keys(cacheKey);
        return keys.size();
    }

    @Override
    public boolean applyMai(Long userId, AppRoomMaiRequest request) {
        Room verify = verify(request.getRoomId());
        R<AppUser> userInfo = remoteAppUserService.getUserInfo(userId, SecurityConstants.APP);
        AppUser data = userInfo.getData();
        Assert.notNull(data, "您无法申请");

        Long count1 = roomMaiRecordService.lambdaQuery()
                .eq(RoomMaiRecord::getRoomId, request.getRoomId())
                .eq(RoomMaiRecord::getType, DynamicConstant.MaiType.MAI)
                .eq(RoomMaiRecord::getUserId, userId)
                .eq(RoomMaiRecord::getStatus, DynamicConstant.CheckStatus.NO)
                .count();
        Assert.isTrue(count1 == 0, "主播正在审核中,请耐心等待");


        if (CommonUtils.isNull(request.getLocation())) {
            List<AppRoomMaiUserResult> maiUsers = CollectionUtils.emptyList();
            if (verify.getRoomTypeId().equals(DynamicConstant.RoomType.Heart_Carve)) {
                maiUsers = this.maiUsers(verify.getId(), request.getType(), false, false, 0L, 7);
            } else {
                maiUsers = this.maiUsers(verify.getId(), request.getType(), false, false, 0L, 0);
            }
            if (maiUsers.isEmpty()) {
                request.setLocation(roomMaiRecordService.getRoomMaiNum(request.getRoomId(), verify.getRoomTypeId()));
            } else {
                List<AppRoomMaiUserResult> sort = CollectionUtil.sort(maiUsers, Comparator.comparing(AppRoomMaiUserResult::getMaiNum).reversed());
                AppRoomMaiUserResult result = sort.get(0);
                request.setLocation(result.getMaiNum() + 1);
            }
        }

        Long count = roomMaiRecordService
                .lambdaQuery()
                .eq(RoomMaiRecord::getRoomId, request.getRoomId())
                .eq(RoomMaiRecord::getMaiNum, request.getLocation())
                .eq(RoomMaiRecord::getStatus, DynamicConstant.IsOnLine.Leave)
                .eq(RoomMaiRecord::getType, request.getType())
                .count();
        Assert.isTrue(count == 0, "此麦位已有人 请更换麦位");

        String key = "";
        if (request.getType().equals(DynamicConstant.MaiType.MAI)) {
            key = CacheKey.ROOM_MAI.getKey(String.valueOf(userId));
        }
        if (request.getType().equals(DynamicConstant.MaiType.LIAN)) {
            key = CacheKey.ROOM_LIAN.getKey(String.valueOf(userId));
        }
        String cacheKey = key.replaceAll("\\{roomNumber}", String.valueOf(verify.getId()));
        AppRoomMaiUserResult result = CacheTemplate.getCache(cacheKey, AppRoomMaiUserResult.class);
        Assert.isNull(result, "请更换麦位!");

        roomMaiRecordService.add(verify.getId(), verify.getRoomNumber(), userId, request.getLocation(),
                request.getType(), DynamicConstant.MaiStatus.Check, data.getPhoto(), data.getNickName(), DynamicConstant.MomentLocation.Heart);
        return true;

    }

    @Override
    public boolean checkMai(Long userId, AppRoomCheckMaiRequest request) {
        Room room = verify(request.getRoomId());
        RoomMaiRecord record = roomMaiRecordService.getById(request.getId());
        Assert.notNull(record, "此记录不存在");

        R<AppUser> userInfo = remoteAppUserService.getUserInfo(record.getUserId(), SecurityConstants.APP);
        AppUser data = userInfo.getData();
        Assert.notNull(data, "此用户不存在");

        Room verify = verify(record.getRoomId());
        Assert.isTrue(record.getStatus().equals(DynamicConstant.MaiStatus.Check), "此记录已审核");

        if (request.getStatus().equals(DynamicConstant.CheckStatus.FENG)) {
            record.setStatus(request.getStatus());
            return roomMaiRecordService.updateById(record);
        }
        if (request.getStatus().equals(DynamicConstant.CheckStatus.YES)) {
            //查询用户是否在频道中 不存在则不需要上麦
            Long count = roomMaiRecordService.lambdaQuery()
                    .eq(RoomMaiRecord::getRoomId, verify.getId())
                    .eq(RoomMaiRecord::getMaiNum, record.getMaiNum())
                    .eq(RoomMaiRecord::getStatus, DynamicConstant.MaiStatus.Pass)
                    .count();
            Assert.isTrue(count == 0, "此麦位已占用 请先下麦此麦位用户再次操作");
            record.setStatus(request.getStatus());
            roomMaiRecordService.updateById(record);
            Assert.isTrue(this.getUserIsChannelStatus(verify.getRoomNumber(), record.getUserId()), "此用户已不在房间");
            this.passUpMai(record.getUserId(), record.getRoomId(), record.getMaiNum(), record.getType(), verify.getGroupId(), verify.getUserId(), record.getStarLocation());
        }
        return true;
    }

    @Override
    public boolean recallMai(Long userId, AppRoomWishCloseRequest request) {
        Room verify = verify(request.getRoomId());
        return roomMaiRecordService.lambdaUpdate()
                .eq(RoomMaiRecord::getRoomId, request.getRoomId())
                .eq(RoomMaiRecord::getUserId, userId)
                .eq(RoomMaiRecord::getStatus, DynamicConstant.MaiStatus.Check)
                .remove();
    }

    @Override
    public AppRoomMaiUserResult verifyMai(Long roomId, Long userId, String cacheKey) {
        Room verify = verify(roomId);
        Assert.isTrue(!verify.getUserId().equals(userId), "您是房主无需开启");
        AppRoomMaiUserResult cache = CacheTemplate.getCache(cacheKey, AppRoomMaiUserResult.class);
        Assert.notNull(cache, "不在麦上");
        return cache;
    }

    @Override
    public String getRoomCacheKey(String key, Long roomId, Long userId) {
        return key.replaceAll("\\{roomNumber}", String.valueOf(roomId));
    }

    @Override
    public boolean inviteMai(Long userId, AppRoomMaiRequest request) {
        Room verify = verify(request.getRoomId());
        Assert.isTrue(verify.getUserId().equals(userId), "您无权限操作");
        this.applyMai(request.getUserId(), request);
        return true;
    }

    @Override
    public boolean getUserIsChannelStatus(String roomNumber, Long userId) {
        String url = rtcConfig.getUserChannelUrl().replaceAll("\\{appid}", rtcConfig.getAppKey())
                .replaceAll("\\{uid}", userId.toString())
                .replaceAll("\\{channelName}", roomNumber);

        HttpHeaders headers = new HttpHeaders();
        headers.set("Authorization", rtcConfig.getAuth());
        try {
            ResponseEntity<String> execute = RestTemplateUtils.execute(url, String.class, headers);
            String body = execute.getBody();
            JSONObject jsonObject = JSONObject.parseObject(execute.getBody());
            String data = jsonObject.getString("data");
            JSONObject json = JSONObject.parseObject(data);
            return json.getBoolean("in_channel");
        } catch (Exception e) {
            return false;
        }
    }

    @Override
    public Pages<CrmRoomInfoResult> crmlistPage(CrmRoomSearchRequest request) {
        Page<Room> roomPage = PageUtils.initPage(request, Room.class);

        Page<Room> page = lambdaQuery()
                .and(StringUtils.hasText(request.getSearch()),
                        wapper -> {
                            wapper.like(Room::getName, request.getSearch())
                                    .or()
                                    .like(Room::getContent, request.getSearch());
                        }
                )
                .orderByDesc(Room::getCreateTime)
                .page(roomPage);
        return PageUtils.pages(roomPage, getCrmInfo(page.getRecords()));
    }

    @Override
    public boolean updateType(AppRoomUpdateTypeRequest request, Long userId) {
        Room verify = verify(request.getRoomId());
        Assert.isTrue(verify.getUserId().equals(userId), "您无权操作");
        RoomType roomType = iRoomTypeService.verify(request.getRoomTypeId());
        verify.setRoomTypeId(request.getRoomTypeId());
        verify.setRoomTypeName(roomType.getName());
        updateById(verify);
        CacheTemplate.setCache(CacheKey.ROOM_INFO.getKey(String.valueOf(verify.getId())), verify, 1L, TimeUnit.DAYS);
        return true;
    }

    @Override
    public void banByUser(AppRoomBanByUserRequest request, Long userId) {
        Room verify = verify(request.getRoomId());
        if (!verify.getUserId().equals(userId)) {
            if (request.getType().equals(DynamicConstant.PermissionIds.Ban)) {
                Assert.isTrue(iRoomUserPostPermissionService.isPermissionByRoomIdAndUserId(request.getRoomId(), userId, DynamicConstant.PermissionIds.Ban), "您无操作权限请联系主持人");
                messageService.banByUser(verify.getGroupId(), request.getUserId().toString(), request.getTime());
            }
            if (request.getType().equals(DynamicConstant.PermissionIds.BLOCK)) {
                Assert.isTrue(iRoomUserPostPermissionService.isPermissionByRoomIdAndUserId(request.getRoomId(), userId, DynamicConstant.PermissionIds.BLOCK), "您无操作权限请联系主持人");
            }
        }
        iRoomBanUserService.addRecord(request.getRoomId(), request.getUserId(), userId, request.getType());


    }

    @Override
    public void cancelBanUser(AppRoomBanByUserRequest request, Long userId) {
        Room verify = verify(request.getRoomId());
        if (!verify.getUserId().equals(userId)) {
            Assert.isTrue(iRoomUserPostPermissionService.isPermissionByRoomIdAndUserId(request.getRoomId(), userId, DynamicConstant.PermissionIds.Ban), "您无操作权限请联系主持人");
        }
        messageService.cancelBanByUser(verify.getGroupId(), request.getUserId().toString());

        iRoomBanUserService.lambdaUpdate()
                .eq(RoomBanUser::getUserId, request.getUserId())
                .eq(RoomBanUser::getRoomId, request.getRoomId())
                .remove();
    }

    public static String hmacSha256(String message, String secret) {
        try {
            SecretKeySpec signingKey = new SecretKeySpec(secret.getBytes(
                    "utf-8"), "HmacSHA256");
            Mac mac = Mac.getInstance("HmacSHA256");
            mac.init(signingKey);
            byte[] rawHmac = mac.doFinal(message.getBytes("utf-8"));
            return bytesToHex(rawHmac);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }


    public static String bytesToHex(byte[] bytes) {
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < bytes.length; i++) {
            String hex = Integer.toHexString(bytes[i] & 0xFF);
            if (hex.length() < 2) {
                sb.append(0);
            }
            sb.append(hex);
        }
        return sb.toString();
    }


    AppRoomMaiUserResult getMaiUserLeaveStatus(Long userId, Long id, Integer leaveStatus) {
        String room_maiKey = CacheKey.ROOM_MAI.getKey(String.valueOf(userId));
        String cacheKey = room_maiKey.replaceAll("\\{roomNumber}", String.valueOf(id));
        AppRoomMaiUserResult result = CacheTemplate.getCache(cacheKey, AppRoomMaiUserResult.class);
        result.setLeaveStatus(DynamicConstant.CheckStatus.NO);
        CacheTemplate.setCache(cacheKey, result, 1L, TimeUnit.DAYS);
        return result;
    }

    @Override
    public JSONObject webHookMessage(AppShengWebHookRequest request, String sign) {
        log.info("离开频道类型-------------type={}", request.getEventType());
        String requestSign = hmacSha256(JSONObject.toJSONString(request), "-h6NhXulO");
//        Assert.isTrue(requestSign.equals(sign), "签名解密失败");

        String key = CacheKey.ROOM_WEBHOOK.getKey(request.getNoticeId());
        String cache = CacheTemplate.getCache(key);
        Assert.isNull(cache, "此消息通知是重复通知");
        CacheTemplate.setCache(key, request.getNoticeId(), 1L, TimeUnit.DAYS);
        String channelName = request.getPayload().getChannelName();
        String uid = request.getPayload().getUid();
        Room room = getRoomByChannelName(channelName);
        Assert.notNull(room, "房间不存在");


        if (request.getEventType() == 103) {
            //主播加入频道
            AppRoomMaiUserResult result = getMaiUserLeaveStatus(Long.valueOf(uid), room.getId(), DynamicConstant.CheckStatus.NO);
            messageService.sendCustomMessage(room.getUserId().toString(), room.getGroupId(),
                    RoomChatRoomKvConstant.RC_ALL_BROADCAST_MSG, result, RoomChatRoomKvConstant.ROOM_USER_COMEBACK);
        } else if (request.getEventType() == 104 && !Long.valueOf(uid).equals(room.getUserId())) {
            AppRoomMaiUserResult result = getMaiUserLeaveStatus(Long.valueOf(uid), room.getId(), DynamicConstant.CheckStatus.YES);
            this.downMaiAndLineByUser(Long.valueOf(uid), room.getId());
            leaveRoom(Long.valueOf(uid), room);
            //主播离开频道
            messageService.sendCustomMessage(room.getUserId().toString(), room.getGroupId(),
                    RoomChatRoomKvConstant.RC_ALL_BROADCAST_MSG, result, RoomChatRoomKvConstant.XIA_MAI_MSG_TYPE);
        } else if (request.getEventType() == 104 && Long.valueOf(uid).equals(room.getUserId())) {
            AppRoomMaiUserResult result = getMaiUserLeaveStatus(Long.valueOf(uid), room.getId(), DynamicConstant.CheckStatus.YES);
            //主持离开频道
            messageService.sendCustomMessage(room.getUserId().toString(), room.getGroupId(),
                    RoomChatRoomKvConstant.RC_ALL_BROADCAST_MSG, result, RoomChatRoomKvConstant.ROOM_USER_LEAVE);
        } else if (request.getEventType() == 105) {
            this.joinRoomAsync(Long.valueOf(uid), room.getId(), room.getGroupId(), room.getUserId());
            //观众加入频道
        } else if (request.getEventType() == 106) {
            //观众离开频道
            leaveRoom(Long.valueOf(uid), room);
        }
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("code", 200);
        return jsonObject;
    }

    @Override
    public void leaveRoom(Long userId, Room room) {
        //离开记录
        roomRecordService.leave(userId, room.getId());
        String key = CacheKey.ROOM_ONLINE.getKey(String.valueOf(userId));
        String cacheKey = key.replaceAll("\\{roomNumber}", String.valueOf(room.getId()));
        CacheTemplate.clear(cacheKey);

        //更新房间的在线人数
        messageService.updateRoomLineNum(room.getId(), room.getGroupId(), room.getUserId());
    }

    List<CrmRoomInfoResult> getCrmInfo(List<Room> list) {
        return list.stream().map(res -> {
            CrmRoomInfoResult crmRoomInfoResult = new CrmRoomInfoResult();
            BeanUtils.copyProperties(res, crmRoomInfoResult);
            return crmRoomInfoResult;

        }).collect(Collectors.toList());
    }


//    public void destroyRoomRongClound(String roomId, String roomGroupid, String memberId) {
//        GroupModel groupModel = new GroupModel();
//        groupModel.setId(roomGroupid);
//        List<GroupMember> groupMembers = new ArrayList<>();
//        GroupMember groupMember = new GroupMember();
//        groupMember.setId(memberId);
//        groupMember.setGroupId(roomGroupid);
//        groupMembers.add(groupMember);
//        groupModel.setMembers(ArrayUtil.toArray(groupMembers, GroupMember.class));
//        try {
//            Result dismiss = rongCloud.group.dismiss(groupModel);
//            log.info("解散群组返回信息：{}", JSON.toJSONString(dismiss));
//        } catch (Exception e) {
//            e.printStackTrace();
//            log.info("解散群组：{}失败!", roomGroupid);
//        }
//        // 清空麦上用户,K歌房用户麦上玫瑰数量
//        redisTemplate.delete("mai:" + roomId + "*");
//
//        lambdaUpdate()
//                .eq(Room::getRoomMember, memberId)
//                .set(Room::getRoomStatus, 99)
//                .update();
//    }


    @Async
    public void joinRoomAsync(Long userId, Long roomId, String roomGroupid, Long roomUserId) {
        if (!userId.equals(roomUserId)) {
            roomRecordService.add(userId, roomId);
            String key = CacheKey.ROOM_ONLINE.getKey(String.valueOf(userId));
            String cacheKey = key.replaceAll("\\{roomNumber}", String.valueOf(roomId));
            CacheTemplate.setCache(cacheKey, userId, 1L, TimeUnit.DAYS);
            //更新房间在线人数
            messageService.updateRoomLineNum(roomId, roomGroupid, roomUserId);
        }
    }
}
